package com.gkj.blog.business.service.impl;

import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.gkj.blog.business.enums.ArticleStatusEnum;
import com.gkj.blog.business.exception.ArticleException;
import com.gkj.blog.business.service.ArticleService;
import com.gkj.blog.business.vo.condition.ArticleConditionVO;
import com.gkj.blog.business.vo.entity.ArticleVo;
import com.gkj.blog.business.vo.entity.User;
import com.gkj.blog.framework.holder.RequestHolder;
import com.gkj.blog.framework.object.AbstractServiceImpl;
import com.gkj.blog.persistence.mapper.ArticleLookMapper;
import com.gkj.blog.persistence.mapper.ArticleLoveMapper;
import com.gkj.blog.persistence.mapper.ArticleMapper;
import com.gkj.blog.persistence.mapper.ArticleTagsMapper;
import com.gkj.blog.persistence.po.Article;
import com.gkj.blog.persistence.po.ArticleLove;
import com.gkj.blog.persistence.po.Tags;
import com.gkj.blog.util.IpUtil;
import com.gkj.blog.util.RedisUtil;
import com.gkj.blog.util.SessionUtil;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import java.util.*;

@Service
@CacheConfig(cacheNames = "redis")
public class ArticleServiceImpl extends AbstractServiceImpl<ArticleVo,Article> implements ArticleService {

    private ArticleMapper articleMapper;
    @Autowired
    private ArticleLoveMapper articleLoveMapper;
    @Autowired
    private ArticleLookMapper articleLookMapper;
    @Autowired
    private ArticleTagsMapper articleTagsMapper;
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    public void setArticleMapper(ArticleMapper articleMapper) {
        this.articleMapper = articleMapper;
        setBaseMapper(articleMapper);
    }




    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveArticleAndTags(ArticleVo articleVo, Long[] tagList){
        insert(articleVo);
        if(tagList==null)
            return true;
        return articleTagsMapper.insertListArticleTags(tagList,articleVo.getId())>0;
    }

    /**
     * 分页查询
     * @param vo
     * @return
     */
    @Override
    public PageInfo<ArticleVo> findPageBreakByCondition(ArticleConditionVO vo) {
        PageHelper.startPage(vo.getPageNumber(), vo.getPageSize());
        List<Article> list = articleMapper.findPageBreakByCondition(vo);
        if (CollectionUtils.isEmpty(list)) {
            return null;
        }
        PageInfo page = new PageInfo<>(list);
        List<ArticleVo> listVo=new ArrayList<ArticleVo>();
        list.forEach(article ->{listVo.add(new ArticleVo(article));});
        page.setList(listVo);
        return page;
    }

    /**
     * 推荐
     * @param pageSize
     * @return
     */
    @Override
    @Cacheable(key = "'recommended'+#pageSize")
    public List<ArticleVo> listRecommended(int pageSize) {
        ArticleConditionVO vo = new ArticleConditionVO();
        vo.setRecommended(true);
        vo.setStatus(ArticleStatusEnum.PUBLISHED);
        vo.setPageSize(pageSize);
        PageInfo pageInfo = this.findPageBreakByCondition(vo);
        return null == pageInfo ? null : pageInfo.getList();
    }

    /**
     * 近期文章
     * @param pageSize
     * @return
     */
    @Override
    public PageInfo<ArticleVo> listRecent(int pageNum,int pageSize) {
        ArticleConditionVO vo = new ArticleConditionVO();
        vo.setPageNumber(pageNum);
        vo.setPageSize(pageSize);
        vo.setStatus(ArticleStatusEnum.PUBLISHED);
        return this.findPageBreakByCondition(vo);
    }

    /**
     * 随机文章
     *
     * @param pageSize
     * @return
     */
    @Override
    public List<ArticleVo> listRandom(int pageSize) {
        ArticleConditionVO vo = new ArticleConditionVO();
        vo.setRandom(true);
        vo.setStatus(ArticleStatusEnum.PUBLISHED);
        vo.setPageSize(pageSize);
        PageInfo pageInfo = this.findPageBreakByCondition(vo);
        return null == pageInfo ? null : pageInfo.getList();
    }

    /**
     * 根据某篇文章获取与该文章相关的文章<br>
     * 搜索同类型、同标签下的文章
     * @param pageSize
     * @param articleId
     * @return
     */
    @Override
    public List<ArticleVo> listRelatedArticle(int pageSize,Long articleId) {
        Article article=articleMapper.selectByPrimaryKey(articleId);
        if (null == article) {
            return listRandom(pageSize);
        }
        ArticleConditionVO vo = new ArticleConditionVO();
        vo.setStatus(ArticleStatusEnum.PUBLISHED);
        List<Tags> tags = article.getTags();
        if (!CollectionUtils.isEmpty(tags)) {
            List<Long> tagIds = new ArrayList<>();
            for (Tags tag : tags) {
                tagIds.add(tag.getId());
            }
            vo.setTagIds(tagIds);
        }
        vo.setTypeId(article.getTypeId());
        vo.setPageSize(pageSize);
        PageInfo pageInfo = this.findPageBreakByCondition(vo);
        return null == pageInfo ? null : pageInfo.getList();
    }

    /**
     * 搜索含有指定标签集合的文章
     * @param pageNum
     * @param pageSize
     * @param tagsIds
     * @return
     */
    public PageInfo<ArticleVo> listFiltrateArticle(int pageNum,int pageSize,List<Long> tagsIds){
        ArticleConditionVO vo=new ArticleConditionVO();
        vo.setStatus(ArticleStatusEnum.PUBLISHED);
        vo.setTagIds(tagsIds);
        vo.setIncludeAllTags(true);
        vo.setPageNumber(pageNum);
        vo.setPageSize(pageSize);
        return this.findPageBreakByCondition(vo);
    }

    /**
     * 获取上一篇和下一篇
     * @return
     */
    public Map<String, ArticleVo> getPrevAndNextArticles(Long id) {
        ArticleVo articleVo=select(id);
        if(articleVo==null)return null;
        List<Article> entityList = articleMapper.getPrevAndNextArticles(articleVo.getCreateTime());
        if (CollectionUtils.isEmpty(entityList)) {
            return null;
        }
        Map<String, ArticleVo> resultMap = new HashMap<>();
        for (Article entity : entityList) {
            if (entity.getCreateTime().getTime() < articleVo.getCreateTime().getTime()) {
                resultMap.put("prev", new ArticleVo(entity));
            } else {
                resultMap.put("next", new ArticleVo(entity));
            }
        }
        return resultMap;
    }

    /**
     * 文章点赞
     * @param id
     */
    @Override
    public void doPraise(Long id) {
        String ip = IpUtil.getRealIp(RequestHolder.getRequest());
        String key = ip + "_doPraise_" + id;
        if(redisUtil.exists(key)){
            throw new ArticleException("一个小时内只能点一次赞哟！");
        }
        User user = SessionUtil.getUser();
        ArticleLove love = new ArticleLove();
        if (null != user) {
            love.setUserId(user.getId());
        }
        love.setArticleId(id);
        love.setUserIp(ip);
        love.setLoveTime(new Date());
        love.setCreateTime(new Date());
        love.setUpdateTime(new Date());
        articleLoveMapper.insertSelective(love);
        redisUtil.set(key,1,60*60L);
    }

    /**
     * 是否存在文章
     * @param id
     * @return
     */
    @Override
    public boolean isExist(Long id) {
        Integer count = articleMapper.isExist(id);
        return count != null && count > 0;
    }

    /**
     * 获取素材库
     *
     * @return
     */
    @Override
    public PageInfo<String> listMaterial(Integer pageNum) {
        PageHelper.startPage(pageNum,20);
        PageInfo pageInfo=new PageInfo(articleMapper.listMaterial());
        return pageInfo;
    }

    /**
     * 回收
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean recycle(Long[] ids) {
        if(ids==null||ids.length==0){
            return false;
        }
        for(Long id:ids){
            ArticleVo articleVo=select(id);
            articleVo.setStatus(ArticleStatusEnum.getRecycle(articleVo.getStatus()).getCode());
            update(articleVo);
        }
        return true;
    }

    /**
     * 还原
     * @param ids
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean recover(Long[] ids) {
        if(ids==null||ids.length==0){
            return false;
        }
        for(Long id:ids){
            ArticleVo articleVo=select(id);
            articleVo.setStatus(ArticleStatusEnum.getRecover(articleVo.getStatus()).getCode());
            update(articleVo);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateArticleAndTags(ArticleVo articleVo, Long[] tagList) {
        update(articleVo);
        articleTagsMapper.deleteByArticleId(articleVo.getId());
        articleTagsMapper.insertListArticleTags(tagList,articleVo.getId());
        return true;
    }

    /**
     * 获取热门文章
     * @return
     */
    @Override
    @Cacheable(key="'hot_'+#pageSize")
    public List<ArticleVo> listHotArticle(int pageSize) {
        PageHelper.startPage(1, pageSize);

        List<Article> entityList = articleMapper.listHotArticle();
        if (CollectionUtils.isEmpty(entityList)) {
            return null;
        }
        List<ArticleVo> list = new ArrayList<>();
        for (Article entity : entityList) {
            list.add(new ArticleVo(entity));
        }
        return list;
    }




    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Long id) {
        articleLookMapper.deleteByArticleId(id);
        articleLoveMapper.deleteByArticleId(id);
        articleTagsMapper.deleteByArticleId(id);
        return articleMapper.deleteByPrimaryKey(id)>0;
    }

}
